package com.iot.lemon.service.impl;

import java.math.BigDecimal;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.dubbo.config.annotation.Service;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.iot.lemon.mapper.TOrderMapper;
import com.iot.lemon.model.TArea;
import com.iot.lemon.model.TBuilding;
import com.iot.lemon.model.THouse;
import com.iot.lemon.model.TOrder;
import com.iot.lemon.model.TVillage;
import com.iot.lemon.service.SysParamService;
import com.iot.lemon.service.TAreaService;
import com.iot.lemon.service.TBuildingService;
import com.iot.lemon.service.THouseService;
import com.iot.lemon.service.TOrderService;
import com.iot.lemon.service.TVillageService;

import top.ibase4j.core.Constants;
import top.ibase4j.core.base.BaseServiceImpl;
import top.ibase4j.core.exception.BusinessException;
import top.ibase4j.core.support.Pagination;
import top.ibase4j.core.support.generator.Sequence;
import top.ibase4j.core.support.pay.WxPayment;
import top.ibase4j.core.util.AlipayUtil;
import top.ibase4j.core.util.CacheUtil;
import top.ibase4j.core.util.DataUtil;
import top.ibase4j.core.util.DateUtil;
import top.ibase4j.core.util.DateUtil.DATE_PATTERN;
import top.ibase4j.core.util.InstanceUtil;
import top.ibase4j.core.util.PropertiesUtil;
import top.ibase4j.core.util.QrcodeUtil;
import top.ibase4j.core.util.ThreadUtil;
import top.ibase4j.core.util.UploadUtil;
import top.ibase4j.core.util.WeChatUtil;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author ShenHuaJie
 * @since 2018-09-19
 */
@Service(interfaceClass = TOrderService.class)
@CacheConfig(cacheNames = "TOrder")
public class TOrderServiceImpl extends BaseServiceImpl<TOrder, TOrderMapper> implements TOrderService {
    @Autowired
    private SysParamService sysParamService;
    @Autowired
    private TVillageService villageService;
    @Autowired
    private TAreaService areaService;
    @Autowired
    private TBuildingService buildingService;
    @Autowired
    private THouseService houseService;

    @Override
    public TOrder update(TOrder record) {
        if (DataUtil.isEmpty(record.getOrderNo())) {
            String orderNo = "T" + DateUtil.getDateTime(DATE_PATTERN.YYYYMMDD) + Sequence.next();
            record.setOrderNo(orderNo);
        }
        return super.update(record);
    }

    @Override
    public Pagination<TOrder> query(Map<String, Object> params) {
        Pagination<TOrder> page = super.query(params);
        for (TOrder order : page.getRecords()) {
            if (order.getHouseId() != null) {
                THouse house = houseService.queryById(order.getHouseId());
                if (house != null) {
                    TBuilding building = buildingService.queryById(house.getBuildingId());
                    if (building != null) {
                        TArea area = areaService.queryById(building.getAreaId());
                        if (area != null) {
                            order.setHouseNo(
                                area.getAreaName() + "-" + building.getBuildingName() + "-" + house.getHouseNo());
                        } else {
                            order.setHouseNo(building.getBuildingName() + "-" + house.getHouseNo());
                        }
                    } else {
                        order.setHouseNo(house.getHouseNo());
                    }
                }
            }
        }
        return page;
    }

    @Override
    @Transactional
    public TOrder updateOrder(TOrder record) {
        String key = Constants.CACHE_NAMESPACE + "ORDER-STATE-" + record.getId();
        String requestId = Sequence.next().toString();
        if (CacheUtil.getLock(key, requestId, 60 * 60 * 24)) {
            TOrder order = queryById(record.getId());
            if (BizType.CAR_STOP_FEE.equals(order.getBizType())) {

            } else if (BizType.CAR_RECHARGE.equals(order.getBizType())) {

            }
            TVillage village = villageService.queryById(order.getVillageId());
            if (PayType.WECHAT.equals(record.getPayType())) {
                String callBack = sysParamService.getValue("WX-PAY-CALLBACK");
                Map<String, String> result = WeChatUtil.pushOrder(village.getWxMchId(), village.getWxMchId(),
                    village.getWxSignKey(), "NATIVE", order.getOrderNo(), record.getRemark(), null,
                    order.getOrderMoney(), null, record.getClientIP(), callBack, null);
                order.setPayOrderId(result.get("prepayId"));
                String codeUrl = result.get("codeUrl");
                String filePath = QrcodeUtil.createQrcode("/usr/temp", codeUrl);
                order.setPayQrcode(UploadUtil.remove2FDFS(filePath).getRemotePath());
            } else if (PayType.ALIPAY.equals(record.getPayType())) {
                String callBack = sysParamService.getValue("ALI-PAY-CALLBACK");
                AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                    village.getAliAppid(), village.getAliPrivateKey(), "json", "UTF-8", village.getAliPublicKey(),
                        "RSA2");
                String codeUrl = AlipayUtil.precreate(alipayClient, order.getOrderNo(), record.getRemark(), null,
                    order.getOrderMoney(), record.getClientIP(), "10m", callBack);
                String filePath = QrcodeUtil.createQrcode("/usr/temp", codeUrl);
                order.setPayQrcode(UploadUtil.remove2FDFS(filePath).getRemotePath());
            }
            return super.update(order);
        } else {
            ThreadUtil.sleep(100, 1000);
            return updateOrder(record);
        }
    }

    @Override
    public void updateWxPayReturn(Map<String, Object> param) {
        Map<String, String> params = InstanceUtil.newHashMap();
        for (String key : param.keySet()) {
            params.put(key, param.get(key).toString());
        }
        String signStr = params.get("sign");
        String sign = WxPayment.createSign(params, PropertiesUtil.getString("wx.partnerKey"));
        if (!sign.equals(signStr)) {
            throw new RuntimeException("参数错误.");
        }
        String return_code = params.get("return_code");
        if (WxPayment.codeIsOK(return_code)) {
            String orderNo = params.get("out_trade_no");
            TOrder order = new TOrder();
            order.setOrderNo(orderNo);
            order = selectOne(order);
            if (order == null) {
                throw new RuntimeException("商户订单号错误.");
            }
            if ("1".equals(order.getState())) {
                order.setPayOrderId(params.get("transaction_id"));
                order.setPayTime(DateUtil.stringToDate(params.get("time_end")));
                order.setPayResult("SUCCESS".equals(params.get("result_code")) ? "1" : "2");
                order = updatePayResult(order, false);
            }
        }
    }

    @Override
    public void updateAliPayReturn(Map<String, Object> param) {
        String outTradeNo = (String)param.get("out_trade_no");
        String tradeNo = (String)param.get("trade_no");
        String subjects = (String)param.get("subject");
        String total_amount = (String)param.get("total_amount");
        String ips = (String)param.get("ip");
        String tradeStatus = (String)param.get("trade_status");
        String gmtCreate = (String)param.get("gmt_create");
        String sign = AlipayUtil.getSign(outTradeNo, subjects, null, new BigDecimal(total_amount), ips, "1D",
                "http://www.heiche.me/app/order/aliPayReturn.api");
        if (param.get("sign").toString().equals(sign)) {
            throw new BusinessException("参数错误.");
        }
        TOrder order = new TOrder();
        order.setOrderNo(outTradeNo);
        order = selectOne(order);
        if (order == null) {
            throw new RuntimeException("商户订单号错误.");
        }
        if ("1".equals(order.getState())) {
            order.setPayOrderId(tradeNo);
            order.setPayTime(DateUtil.stringToDate(gmtCreate));
            order.setPayResult("TRADE_SUCCESS".equals(tradeStatus) ? "1" : "2");
            order = updatePayResult(order, false);
        }
    }

    // 支付成功后发送通知
    @Transactional
    public TOrder updatePayResult(TOrder order, boolean isSearch) {
        String key = Constants.CACHE_NAMESPACE + "ORDER-STATE-" + order.getOrderNo();
        String requestId = Sequence.next().toString();
        if (CacheUtil.getLock(key, requestId, 60 * 60 * 24)) {
            try {
                TOrder record = super.queryById(order.getId());
                if ("1".equals(record.getState()) && "1".equals(order.getPayResult())) {
                    order.setState("3");
                    order = super.update(order);
                    return order;
                } else if (!isSearch) {
                    return super.update(order);
                } else {
                    return record;
                }
            } finally {
                CacheUtil.unLock(key, requestId);
            }
        } else if (isSearch) {
            ThreadUtil.sleep(100, 2000);
            order = updatePayResult(order, isSearch);
        }
        return order;
    }
}
